package LunaServer.util;

import java.time.Instant;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Random;

/**
 * 验证码管理器
 * 使用内存存储验证码，避免数据库IO操作
 */
public class VerificationCodeManager {
    // 使用线程安全的HashMap存储验证码
    private static final Map<String, VerificationCodeInfo> codeStorage = new ConcurrentHashMap<>();
    
    // 验证码默认有效期（分钟）
    private static final int DEFAULT_EXPIRE_MINUTES = 10;
    
    /**
     * 生成并存储验证码
     * @param email 邮箱地址
     * @param length 验证码长度
     * @return 生成的验证码
     */
    public static String generateAndStoreCode(String email, int length) {
        // 清理过期的验证码
        cleanupExpiredCodes();
        
        // 生成验证码
        String code = generateCode(length);
        
        // 存储验证码信息
        Instant expireTime = Instant.now().plusSeconds(DEFAULT_EXPIRE_MINUTES * 60);
        codeStorage.put(email, new VerificationCodeInfo(code, expireTime, false));
        
        return code;
    }
    
    /**
     * 验证验证码
     * @param email 邮箱地址
     * @param code 验证码
     * @return 验证结果
     */
    public static VerificationResult verifyCode(String email, String code) {
        // 清理过期的验证码
        cleanupExpiredCodes();
        
        VerificationCodeInfo codeInfo = codeStorage.get(email);
        if (codeInfo == null) {
            return new VerificationResult(false, "验证码不存在或已过期");
        }
        
        // 检查是否已使用
        if (codeInfo.isUsed) {
            return new VerificationResult(false, "验证码已被使用");
        }
        
        // 检查是否过期
        if (Instant.now().isAfter(codeInfo.expireTime)) {
            // 从存储中移除过期的验证码
            codeStorage.remove(email);
            return new VerificationResult(false, "验证码已过期");
        }
        
        // 验证码是否正确
        if (!codeInfo.code.equals(code)) {
            return new VerificationResult(false, "验证码不正确");
        }
        
        // 标记为已使用
        codeInfo.isUsed = true;
        
        return new VerificationResult(true, "验证成功");
    }
    
    /**
     * 重新发送验证码（不改变原验证码的过期时间）
     * @param email 邮箱地址
     * @param length 验证码长度
     * @return 验证码或null（如果原验证码仍然有效）
     */
    public static String resendCode(String email, int length) {
        // 清理过期的验证码
        cleanupExpiredCodes();
        
        VerificationCodeInfo codeInfo = codeStorage.get(email);
        if (codeInfo != null && !codeInfo.isUsed && 
            Instant.now().isBefore(codeInfo.expireTime)) {
            // 原验证码仍然有效，直接返回null表示不需要重新生成
            return null;
        }
        
        // 生成新验证码
        String code = generateCode(length);
        Instant expireTime = Instant.now().plusSeconds(DEFAULT_EXPIRE_MINUTES * 60);
        codeStorage.put(email, new VerificationCodeInfo(code, expireTime, false));
        
        return code;
    }
    
    /**
     * 清理过期的验证码
     */
    private static void cleanupExpiredCodes() {
        Instant now = Instant.now();
        codeStorage.entrySet().removeIf(entry -> 
            now.isAfter(entry.getValue().expireTime) || entry.getValue().isUsed);
    }
    
    /**
     * 生成随机验证码
     * @param length 验证码长度
     * @return 随机验证码
     */
    private static String generateCode(int length) {
        String characters = "0123456789";
        Random random = new Random();
        StringBuilder code = new StringBuilder();
        
        for (int i = 0; i < length; i++) {
            code.append(characters.charAt(random.nextInt(characters.length())));
        }
        
        return code.toString();
    }
    
    /**
     * 验证码信息类
     */
    private static class VerificationCodeInfo {
        final String code;
        final Instant expireTime;
        boolean isUsed;
        
        VerificationCodeInfo(String code, Instant expireTime, boolean isUsed) {
            this.code = code;
            this.expireTime = expireTime;
            this.isUsed = isUsed;
        }
    }
    
    /**
     * 验证结果类
     */
    public static class VerificationResult {
        public final boolean isValid;
        public final String message;
        
        public VerificationResult(boolean isValid, String message) {
            this.isValid = isValid;
            this.message = message;
        }
    }
}